#include "serverconnection.h"

ServerConnection::ServerConnection(QObject *parent) :
    QObject(parent)
{
    qDebug() << "ServerConnection::ServerConnection()";
    FreeClientId = 1;
    ptcpServer = new QTcpServer(this);
}

ServerConnection::~ServerConnection()
{
    qDebug() << "ServerConnection::~ServerConnection";
    stop();
    delete ptcpServer;
}

const QString ServerConnection::getIP()
{
    qDebug() << "Server Ip= "
             << ptcpServer->serverAddress().toString();
    return ptcpServer->serverAddress().toString();
}

void ServerConnection::setPort(int _port)
{
    qDebug() << "ServerConnection::setPort(int _port)";
    Port = _port;
}

void ServerConnection::run()
{
    qDebug() << "ServerConnection::run()";
    if(!ptcpServer->listen(QHostAddress::Any,Port))
    {
        emit signalConnectionError();
        qDebug() << "ServerConnection::run:: ptcpServer->close()";
        ptcpServer->close();
    }

    connect(ptcpServer, SIGNAL(newConnection()),
            this, SLOT(slotNewConnection()));
}

void ServerConnection::stop()
{
    qDebug() << "ServerConnection::stop()";

    foreach(int i, TcpClients.keys())
    {
        TcpClients[i]->close();
    }
    TcpClients.clear();
    TcpPlayers.clear();
    ClientsBuffer.clear();

    ptcpServer->close();
    qDebug() << "Server stop\n";

}

void ServerConnection::sendToClient(QTcpSocket *pClientSocket, const QString str)
{
    qDebug() << "ServerConnection sendToClient (" << str <<")\n";
    QByteArray  arrBlock;
    QDataStream out(&arrBlock, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_8);

    out << quint16(0);

    out << str.toUtf8();
    out.device()->seek(0);
    out << quint16(arrBlock.size() - sizeof(quint16));

    pClientSocket->write(arrBlock);
}

void ServerConnection::sendToClient(int localId, const QString str)
{
    sendToClient(TcpClients[localId], str);
}

void ServerConnection::sendToPlayer(int playerId, const QString str)
{
    sendToClient(TcpPlayers[playerId], str);
}

void ServerConnection::sendToAllPlayers(const QString str)
{
    foreach(int i, TcpPlayers.keys())
    {
        sendToClient(TcpPlayers[i], str);
    }
}

void ServerConnection::sendToAllSockets(const QString str)
{
    foreach(int i, TcpClients.keys())
    {
        sendToClient(TcpClients[i], str);
    }

}

void ServerConnection::gameStarts()
{
    qDebug() << "ServerConnection::gameStarts()";
    stopNewConnections();
    breakNotPlayerConnections();
}

void ServerConnection::stopNewConnections()
{
    qDebug() << "ServerConnection::stopNewConnections()";
    disconnect(ptcpServer, SIGNAL(newConnection()),
               this, SLOT(slotNewConnection()));
}

void ServerConnection::breakNotPlayerConnections()
{
    qDebug() << "ServerConnection::breakNotPlayerConnections()";
    foreach(int i, TcpClients.keys())
    {
        if (!LocalIdToTankId.contains(i))
        {
            disconnect(TcpClients[i], SIGNAL(readyRead()),
                this, SLOT(slotReadClient()));
            TcpClients[i]->close();
            ClientsBuffer.remove(i);
        }
    }
}

void ServerConnection::addPlayer(int localId, int playerId)
{
    qDebug() << "ServerConnection::addPlayer(int localId, int playerId)"
             << localId << ","
             << playerId;
    TcpPlayers[playerId] = TcpClients[localId];
    LocalIdToTankId[localId] = playerId;
}

void ServerConnection::slotNewConnection()
{
    qDebug() << "ServerConnection::slotNewConnection()";
    QTcpSocket* pClientSocket = ptcpServer->nextPendingConnection();
    int localId = FreeClientId++;
    TcpClients[localId] = pClientSocket;
    TcpClients[localId]->setObjectName(QString("%1").arg(localId));
    ClientsBuffer[localId] = "";
    connect(TcpClients[localId], SIGNAL(disconnected()),
            this, SLOT(slotDeleteFromTcpClient()));
    connect(TcpClients[localId], SIGNAL(disconnected()),
            TcpClients[localId], SLOT(deleteLater()));
    connect(TcpClients[localId], SIGNAL(readyRead()),
            this, SLOT(slotReadClient()));
}

void ServerConnection::slotReadClient()
{
    qDebug() << "ServerConnection::slotReadClient()";
    QTcpSocket* pClientSocket = (QTcpSocket*)sender();
    QDataStream in(pClientSocket);
    in.setVersion(QDataStream::Qt_4_8);
    quint16 m_nNextBlockSize = 0;
    for (;;)
    {
        if (!m_nNextBlockSize)
        {
            if (pClientSocket->bytesAvailable() < sizeof(quint16))
            {
                break;
            }
            in >> m_nNextBlockSize;
        }

        if (pClientSocket->bytesAvailable() < m_nNextBlockSize)
        {
            break;
        }

        QByteArray data;
        in >> data;



        int localId = pClientSocket->objectName().toInt();
        ClientsBuffer[localId].append(data);

        int pos = ClientsBuffer[localId].indexOf(delimetrs::eom);
        while (pos != -1)
        {
            QString str = ClientsBuffer[localId].left(pos+2);
            ClientsBuffer[localId].remove(0,pos+2);


            if (ClientsBuffer.size() > 0)
            {
                //if next message allready exists
                //then we should remove first 16bits(message length)
                //size of quint16 = 16bit, and size of QChar = 16bit
                ClientsBuffer[localId].remove(0,1);
            }

            if (TcpPlayers.contains(localId))
            {
                int playerId = LocalIdToTankId[localId];
                emit signalReceivedFromPlayer(playerId, str);
                qDebug() << "ServerConnection signalReceivedFromClient"
                         << "( localId="
                         << localId
                         << " playerId="
                         << playerId
                         << " str="
                         << str
                         << ")";

            }
            else
            {
                emit signalReceivedFromClient(localId, str);
                qDebug() << "ServerConnection signalReceivedFromClient"
                         << "( localId="
                         << localId
                         << "str="
                         << str
                         << ")";

            }
            pos = ClientsBuffer[localId].indexOf(delimetrs::eom);
        }
        m_nNextBlockSize = 0;
    }

}

void ServerConnection::slotDeleteFromTcpClient()
{
    qDebug() << "ServerConnection::slotDeleteFromTcpClient()";
    QTcpSocket* pClientSocket = (QTcpSocket*)sender();
    disconnect(pClientSocket, SIGNAL(readyRead()),
               this, SLOT(slotReadClient()));
    int localId = pClientSocket->objectName().toInt();
    if (LocalIdToTankId.contains(localId))
    {
        int playerId = LocalIdToTankId[localId];
        emit signalPlayerDisconnected(playerId);
        TcpPlayers.remove(playerId);
        LocalIdToTankId.remove(localId);
    }
    else
    {
        emit signalClientDisconnected(localId);
    }
    ClientsBuffer.remove(localId);
    TcpClients.remove(localId);
}
